<?php
/**
 * Created by PhpStorm.
 * User: xuho
 * Date: 2019-11-21
 * Time: 15:55
 */

namespace extend\redis;


abstract class RingQueue
{
    public $redis;
    public $name = '';
    public $prefix = '';

    public function __construct()
    {
        $this->redis = Redis::instance();
    }


    /**
     * 设置值，最终拼接json
     * @param array $taskValue 队列值
     * @return bool
     */
    public function set(array $taskValue)
    {
        if (empty($taskValue)) {
            return false;
        }

        if (!is_array($taskValue)) {
            return false;
        }

        // 任务名字
        $taskName = $this->prefix . $this->name;
        // 任务对应指针的名字
        $pointName = $this->prefix . 'point_' . $this->name;

        // 判断对应的指针存不存在，不存在就返回false
        if (!$this->redis->exists($pointName)) {
            return false;
        }

        // 获取当前的指针的位置和圈数
        $point = $this->redis->hMGet($pointName, ['point', 'cycle_num']);

        // 添加圈数
        ++$point['cycle_num'];
        $taskKey = "{$point['cycle_num']}_{$point['point']}";
        $task = [];
        if ($this->redis->hExists($taskName, $taskKey)) {
            $task = $this->redis->hGet($taskName, $taskKey);
            $task = json_decode($task, true) ?: [];
        }

        $task = json_encode(array_merge($task, $taskValue), JSON_FORCE_OBJECT);
        $this->redis->hSet($taskName, $taskKey, $task);
    }


    /**
     * 获取值
     * @param  string $slotNum 环形块数量
     */
    public function get($slotNum)
    {
        // 任务名字
        $taskName = $this->prefix . $this->name;
        // 任务对应指针的名字
        $pointName = $this->prefix . 'point_' . $this->name;

        // 判断指针对应的键有没有存在
        if (!$this->redis->exists($pointName)) {
            $point = ['point' => 1, 'cycle_num' => '1'];
            $this->redis->hMset($pointName, $point);
        } else {
            // 获取当前环形队列的位置
            $point = $this->redis->hMGet($pointName, ['point', 'cycle_num']);
            // 判断环形队列当前的值是多少，如果大于设定的环形的值就把环数+1
            if ($point['point'] < $slotNum) {
                $point = ['point' => ++$point['point'], 'cycle_num' => $point['cycle_num']];
            } else {
                // 否则指针从1开始，圈数加1
                $point = ['point' => 1, 'cycle_num' => ++$point['cycle_num']];
            }
            // 设置指针值和圈数
            $this->redis->hMset($pointName, $point);
        }

        $taskValue = '';
        // 获取环形队列的值
        $taskKey = "{$point['cycle_num']}_{$point['point']}";
        if ($this->redis->hExists($taskName, $taskKey)) {
            $taskValue = $this->redis->hGet($taskName, $taskKey);
            $this->redis->hDel($taskName, $taskKey);
        }

        $this->execute($taskValue);
    }

    abstract function execute($task);
}